<script setup lang="ts">
import {computed, onBeforeUnmount, shallowRef} from 'vue'
import {registerDSQL} from './dsql.ts'
import {defineDsqlThemes} from './theme-dsql.ts'

// 对外暴露的属性
const props = withDefaults(defineProps<{
  modelValue: string
  lang?: 'dsql' | 'json' | 'xml' | 'yaml' | 'sql' | 'javascript' | 'typescript' | 'text'
  theme?: 'vs-dark' | 'vs' | 'hc-black'
  options?: Record<string, any>
}>(), {
  modelValue: '',
  lang: 'dsql',
  theme: 'vs-dark',
  options: () => ({automaticLayout: true, fontSize: 14, minimap: {enabled: true}}),
})

const emit = defineEmits<{
  'update:modelValue': [value: string]
}>()

// v-model 透传
const modelValueProxy = computed({
  get: () => props.modelValue,
  set: (v: string) => emit('update:modelValue', v),
})

const editorRef = shallowRef<any>()
const monacoRef = shallowRef<any>()

// 统一配置
const mergedOptions = computed(() => ({
  ...props.options,
  ...({
    automaticLayout: true,
    autoIndent: 'full',
    acceptSuggestionOnEnter: 'off',
    // 可选优化：
    snippetSuggestions: 'inline',  // 避免 snippet 顶在最上面
    tabSize: 4,
    insertSpaces: false,
  })
}))

// 语言解析：
// - dsql：自定义语言（需要下方 registerDSQL）
// - json/xml/sql/js/ts：Monaco 内置（注意：本地打包时需确保对应 language contribution 已引入）
// - yaml：需要 monaco-yaml（见下文）
const resolvedLanguage = computed(() => {
  switch (props.lang) {
    case 'dsql':
      return 'dsql'
    case 'json':
      return 'json'
    case 'xml':
      return 'xml'
    case 'yaml':
      return 'yaml'
    case 'sql':
      return 'sql'
    case 'javascript':
      return 'javascript'
    case 'typescript':
      return 'typescript'
    default:
      return 'text'
  }
})

// 仅首次挂载时注册 DSQL 语言/补全
let dsqlRegistered = false
let themesDefined = false

async function handleMount(editor: any, monaco: any) {
  editorRef.value = editor
  monacoRef.value = monaco

  // 注册 DSQL（只注册一次）
  if (!dsqlRegistered) {
    registerDSQL(monaco)
    dsqlRegistered = true
  }

  // 定义主题（只需一次）
  if (!themesDefined) {
    defineDsqlThemes(monaco)
    themesDefined = true
  }

  // （可选）根据需要懒加载一些内置 language 的“contribution”
  // 仅在“本地打包 + 你没有用 CDN”时需要。CDN 方案通常已内置。
  // 例：SQL 与 XML
  await ensureBasicLanguages(monaco, props.lang)

  // 如果默认语言就是 dsql，设置一下（多数情况下不需要，v-model 已处理）
  // const model = editor.getModel()
  // if (model) monaco.editor.setModelLanguage(model, resolvedLanguage.value)

  // 切换主题：dsql-dark 或 dsql-light
  monaco.editor.setTheme('dsql-dark')
}

// 懒加载内置 basic-languages 的贡献（本地打包时）
async function ensureBasicLanguages(monaco: any, lang?: string) {
  // 这些 import 只在本地打包需要，CDN 方案通常自动可用
  if (lang === 'sql') {
    await import('monaco-editor/esm/vs/basic-languages/sql/sql.contribution')
  }
  if (lang === 'xml') {
    await import('monaco-editor/esm/vs/basic-languages/xml/xml.contribution')
  }
  // json/html/css/ts/js 通常已包含（取决于你配置的 worker）
}

onBeforeUnmount(() => {
  // 如果后续注册了 Hover/Diagnostics 等需手动 dispose 的 provider，这里统一释放
  // 当前 registerCompletionItemProvider 被 Monaco 管理，无需额外 dispose
})
</script>

<template>
  <div class="editor-wrap">
    <vue-monaco-editor
        v-model:value="modelValueProxy"
        :language="resolvedLanguage"
        :theme="theme"
        :options="mergedOptions"
        @mount="handleMount"
    />
  </div>
</template>

<style scoped>
.editor-wrap {
  /* 编辑器区域占满父容器 */
  width: 100%;
  height: 100%;
}
</style>
